package cn.bonoon.kernel.menus;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import cn.bonoon.kernel.VisibleScope;
import cn.bonoon.kernel.menus.tips.MenuTipDefinition;
import cn.bonoon.kernel.menus.tips.MenuTipHandler;
import cn.bonoon.kernel.util.StringHelper;
import cn.bonoon.util.PathUtil;

/**
 * 
 * @author jackson
 *
 */
public abstract class AbstractMenuable extends AbstractItemable implements MenuableDefinition, ParentContainer{

	public final static String TARGET_BLANK = "_blank";
	private static final String CLASS_PATH_PREFIX = "class:";
	
	private String classPath;
	
	protected List<MenuDefinitionImpl> menus;
	
	protected ActionDefinition[] actions;

	protected VisibleScope scope;
	
	/** <pre>判断时的格式为二进制的格式，如：010011100011
	 * 当前位置为1，则表示这个操作的权限是有定义的，需要对它进行权限的判断处理，如果为0则表示没有定义过，
	 * 在做操作权限判断时可以认为是可操作的 </pre> */
	protected int actionPrivileges;
	
	protected String attrs;
	protected String target;
	protected String args;
	
	private MenuTipDefinition menuTip;
	
	private MenuTipHandler menuTipHandler;
	
	
	@Override
	public MenuTipHandler tipHandler() {
		return menuTipHandler;
	}
	
//	@Override
//	protected void _button(String href, StringBuilder a, String selected) {
//		super._button(href, a, selected);
//		
//		if(null != menuTip){
//			
//		}
//	}

	public void add(MenuDefinitionImpl menu) {
		if (null == menus){
			menus = new ArrayList<MenuDefinitionImpl>();
		}
		menus.add(menu);
	}
	
	protected String internalParseUrl(PlatformContext platformContext, String parentPath){
		if(StringHelper.isEmpty(href)){
			platformContext.add(this);
			return parentPath;
		}
		
		if(href.startsWith(CLASS_PATH_PREFIX)){
			
			//路径里定义的一个类；这时需要把这个类解析面一个界面
			classPath = href.substring(CLASS_PATH_PREFIX.length());
			href = platformContext.path("/s/sys/information", "!" + id, "index.do");
			platformContext.add(this);
			return parentPath;
		}

		boolean hasFilename = href.endsWith(".do") || href.contains(".do?");
		
		if(href.startsWith("/")){
			href = platformContext.path(href);
		}else{
			//使用相对路径的情况
			href = PathUtil.path(parentPath, href);
			if(hasFilename){
				parentPath = href.substring(0, href.lastIndexOf('/'));
			}else{
				parentPath = href;
			}
		}
		if(!hasFilename){
			href = PathUtil.path(href, "!" + id, "index.do");
		}
	
		if(StringHelper.isNotEmpty(args)){
			if(href.contains("?")){
				href += "&" + args;
			}else{
				href += "?" + args;
			}
		}
		
		platformContext.add(href, this);
		return parentPath;
	}
	
	protected void init(PlatformContext platformContext, ModuleContext moduleContext, ParentContainer parent){
		super.init(platformContext, moduleContext, parent);
		
		this.internalId = platformContext.combine(parent.getInternalId(), id);
		this.id = platformContext.idGenerate(internalId);
		this.path = internalParseUrl(platformContext, parent.getPath());
		
		platformContext.add(this, describe);
		moduleContext.add(id, this);
		
		if(null != menuTip){
			//TODO 有定义了频道或菜单的提示
			try{
				menuTipHandler = menuTip.resolveHandler(platformContext);
//				menuTipHandler = (MenuTipHandler) Class.forName(menuTip.getClassName()).newInstance();
//				if(menuTip.isInChannel()){
//					ChannelDefinitionImpl channel = internalChannel();
//					channel.add(menuTipHandler);
//				}
				
				if(menuTip.isInHome()){
					moduleContext.add(menuTipHandler);
				}
				
				menuTipHandler.init(platformContext, this, menuTip);
			}catch (Exception e) {
				e.printStackTrace();
				//无法生成频道或菜单的提示信息
			}
		}
		
		if(null != menus){
			Collections.sort(menus);
			for(MenuDefinitionImpl menu : menus){
				
				menu.navigation = platformContext.navigateGenerate(this, menu);
				menu.channel = internalChannel();
				
				menu.init(platformContext, moduleContext, this);
			}
		}
		
		//这里对一些初始值进行处理，以系统运行过程中就不需要再去判断，直接引用就可以
		attrs = StringHelper.get(attrs, "");
		
		if(TARGET_BLANK.equalsIgnoreCase(target)){ 
			attrs += " target='_blank'"; 
		}
		
		if(null == actions){
			actions = new ActionDefinition[0];
		}else{
			for(ActionDefinition ad : actions){
				ad.init(platformContext, moduleContext, this);
			}
		}
	}
	
	@Override
	public MenuDefinition loadSubmenu(String... ids) {
		String id = platformContext.combine(internalId, ids);
		id = platformContext.idGenerate(id);
		for(MenuDefinitionImpl menu : menus){
			if(id.equals(menu.id)) return menu;
		}
		return null;
	}
	
	@Override
	public String idSubmenu(String... ids) {
		String id = platformContext.combine(internalId, ids);
		id = platformContext.idGenerate(id);
		return id;
	}
	
	@Override
	public Iterator<MenuDefinition> iterator() {
		if(null != menus) return new ArrayList<MenuDefinition>(menus).iterator();
		return Collections.emptyIterator();
	}
	
	@Override
	public boolean isEmpty() {
		return null == menus || menus.isEmpty();
	}

	public final List<MenuDefinition> getMenus() {
		if(menus == null) return Collections.emptyList();
		return new ArrayList<MenuDefinition>(menus);
	}

	public final void setHref(String href) {
		this.href = href;
	}
	
	public String getClassPath() {
		return classPath;
	}
	
	@Override
	protected void resolveAdditiveAttributes(StringBuilder a) {
		a.append(attrs);
	}
	
	public String getAttrs() {
		return attrs;
	}

	public void setAttrs(String attrs) {
		this.attrs = attrs;
	}

	public void setArgs(String args) {
		this.args = args;
	}
	public final String getTarget() {
		return target;
	}

	public final void setTarget(String target) {
		this.target = target;
	}

	public ActionDefinition[] getActions() {
		return actions;
	}

	public void setActions(ActionDefinition[] actions) {
		this.actions = actions;
	}

	public int getActionPrivileges() {
		return actionPrivileges;
	}

	public void setActionPrivileges(int actionPrivileges) {
		this.actionPrivileges = actionPrivileges;
	}
	
	public VisibleScope getScope() {
		return scope;
	}
	
	public void setScope(VisibleScope scope) {
		this.scope = scope;
	}

	public MenuTipDefinition getMenuTip() {
		return menuTip;
	}

	public void setMenuTip(MenuTipDefinition menuTip) {
		this.menuTip = menuTip;
	}
}
